package com.jmb.waimao.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jmb.waimao.entity.EmailAddress;
import com.jmb.waimao.entity.EmailTask;
import com.jmb.waimao.entity.EmailTemplate;
import com.jmb.waimao.mapper.EmailTaskMapper;
import com.jmb.waimao.service.EmailAddressService;
import com.jmb.waimao.service.EmailSendingService;
import com.jmb.waimao.service.EmailTaskService;
import com.jmb.waimao.service.EmailTemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Implementation of EmailTaskService
 */
@Service
@Slf4j
public class EmailTaskServiceImpl extends ServiceImpl<EmailTaskMapper, EmailTask> implements EmailTaskService {

    @Autowired
    private EmailAddressService emailAddressService;

    @Autowired
    private EmailSendingService emailSendingService;

    @Autowired
    private EmailTemplateService emailTemplateService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public EmailTask createTask(EmailTask emailTask) {
        // Set initial values
        emailTask.setStatus(0); // Created
        emailTask.setSuccessCount(0);
        emailTask.setFailCount(0);

        // Process template if specified
        if (emailTask.getTemplateId() != null) {
            processTemplate(emailTask);
        }

        // Get total count of emails in the target group
        List<EmailAddress> recipients = emailAddressService.getByGroup(emailTask.getTargetGroup());
        emailTask.setTotalCount(recipients.size());

        // Set timestamps
        LocalDateTime now = LocalDateTime.now();
        emailTask.setCreateTime(now);
        emailTask.setUpdateTime(now);
        emailTask.setDeleted(0);

        // Save the task
        save(emailTask);

        return emailTask;
    }

    /**
     * Process email template
     *
     * @param emailTask Email task with template ID and variables
     */
    private void processTemplate(EmailTask emailTask) {
        try {
            // Get template
            EmailTemplate template = emailTemplateService.getById(emailTask.getTemplateId());
            if (template == null) {
                log.error("Template not found: {}", emailTask.getTemplateId());
                return;
            }

            // Apply template variables
            Map<String, String> variables = emailTask.getTemplateVariables();
            if (variables == null) {
                variables = new HashMap<>();
            }

            // Add default variables
            if (!variables.containsKey("date")) {
                variables.put("date", LocalDateTime.now().toString());
            }

            EmailTemplate processedTemplate = emailTemplateService.applyTemplateVariables(
                    emailTask.getTemplateId(), variables);

            // Set subject and content from processed template
            emailTask.setSubject(processedTemplate.getSubject());
            emailTask.setContent(processedTemplate.getContent());

        } catch (Exception e) {
            log.error("Error processing template for task: {}", emailTask.getTaskName(), e);
        }
    }

    @Override
    @Async
    public boolean executeTask(Long taskId) {
        EmailTask task = getById(taskId);
        if (task == null) {
            log.error("Task not found: {}", taskId);
            return false;
        }

        // Update task status to In Progress
        task.setStatus(1);
        task.setUpdateTime(LocalDateTime.now());
        updateById(task);

        // Get recipients
        List<EmailAddress> recipients = emailAddressService.getByGroup(task.getTargetGroup());

        // Initialize counters
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failCount = new AtomicInteger(0);

        // Send emails
        for (EmailAddress recipient : recipients) {
            try {
                boolean success = emailSendingService.sendEmail(recipient, task.getSubject(), task.getContent());

                if (success) {
                    successCount.incrementAndGet();
                } else {
                    failCount.incrementAndGet();
                }

                // Update task status periodically (every 10 emails)
                if ((successCount.get() + failCount.get()) % 10 == 0) {
                    updateTaskProgress(task.getId(), successCount.get(), failCount.get());
                }

                // Add a small delay to avoid overwhelming the mail server
                Thread.sleep(100);

            } catch (Exception e) {
                log.error("Error sending email to {}", recipient.getEmail(), e);
                failCount.incrementAndGet();
            }
        }

        // Update final task status
        task.setSuccessCount(successCount.get());
        task.setFailCount(failCount.get());
        task.setStatus(2); // Completed
        task.setUpdateTime(LocalDateTime.now());
        updateById(task);

        return true;
    }

    @Override
    public EmailTask getTaskStatus(Long taskId) {
        EmailTask task = getById(taskId);
        // Return null if task is deleted or doesn't exist
        if (task == null || task.getDeleted() == 1) {
            return null;
        }
        return task;
    }

    /**
     * Update task progress
     *
     * @param taskId Task ID
     * @param successCount Number of successful emails
     * @param failCount Number of failed emails
     */
    private void updateTaskProgress(Long taskId, int successCount, int failCount) {
        EmailTask task = getById(taskId);
        if (task != null) {
            task.setSuccessCount(successCount);
            task.setFailCount(failCount);
            task.setUpdateTime(LocalDateTime.now());
            updateById(task);
        }
    }
}
